package my.mark.mybaibaoxiang.eventDemo.custom;

import my.mark.mybaibaoxiang.system.Global;
import my.mark.mybaibaoxiang.system.kit.ClassSearcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

/**
 * @Description: 事件驱动模型处理机制插件
 * @Author wxming
 * @Date 2019年3月25日 下午12:24:42
 */
@Configuration
public class EventPlugin{
    private final Logger LOG = LoggerFactory.getLogger(EventPlugin.class);
    // 事件处理
    private EventHandler handler;
    // 线程池
    private ExecutorService pool;

    private List<String> injars = new ArrayList<String>();

    private List<String> inpackages = new ArrayList<String>();
    // 默认要扫描的jar包
    private static String twotigerJar = "twotiger-1.0.0-SNAPSHOT.jar";
    // 默认要扫描的package
    private static String scanPackage = "my.mark.mybaibaoxiang.*.custom.listener";

    public EventPlugin() {
        extendsJar(twotigerJar);
        extendsPackage(scanPackage);
    }

    /**
     * 是否异步处理总线消息
     * 
     * @return
     */
    public EventPlugin asyn() {
        pool = Global.ES;
        return this;
    }

    @org.springframework.context.event.EventListener
    public void FirstEventListener(ContextRefreshedEvent event) {
        try {
            //TODO 如果要异步处理，就需要在最终加载插件前初始化pool：
            //this.asyn();
            // 查找所有extends ActionListener 的类
            List<Class<?>> listenerClasses = ClassSearcher.of(ApplicationListener.class)
                .injars(injars).inPackages(inpackages).search();
            List<Container> containers = new ArrayList<Container>();
            // 遍历添加到Container
            for (Class<?> listener : listenerClasses) {
                //TODO 获取该类的注解，并判断该类是否加了@EventListener注解：
                EventListener eventListener = (EventListener) listener
                    .getAnnotation(EventListener.class);
                if (eventListener == null) {
                    LOG.error("ApplicationListener lack of EventListener's annotation!");
                    break;
                } else {
                    //若关闭则不在加载
                    boolean stop = eventListener.stop();
                    if (stop)
                        continue;
                    // 获取事件类型
                    Class<? extends ApplicationEvent> type = null;
                    Type[] interfaceTypes = listener.getGenericInterfaces();
                    for (Type t : interfaceTypes) {
                        if (t instanceof ParameterizedType) {
                            ParameterizedType pt = (ParameterizedType) t;
                            // 接口
                            Class<?> rawType = (Class<?>) pt.getRawType();
                            if (rawType.getName().equals(ApplicationListener.class.getName())) {
                                // 接口泛型
                                type = (Class<? extends ApplicationEvent>) pt
                                    .getActualTypeArguments()[0];
                            }
                        }
                    }
                    if (type == null) {
                        LOG.error("ApplicationListener lack of ApplicationEvent!");
                        break;
                    }
                    int priority = eventListener.priority();
                    ApplicationListener<? extends ApplicationEvent> al = (ApplicationListener<? extends ApplicationEvent>) listener
                        .newInstance();
                    Container container = new Container(priority, type, al);
                    containers.add(container);
                    LOG.info("EventPlugin add ApplicationListener [" + listener.getName()
                             + "] success.");
                }
            }
            // 按照优先级排序
            Collections.sort(containers, new ContainerComparator());
            // 合并队列
            Map<Class<? extends ApplicationEvent>, List<ApplicationListener<? extends ApplicationEvent>>> mlisteners = new ConcurrentHashMap<Class<? extends ApplicationEvent>, List<ApplicationListener<? extends ApplicationEvent>>>();
            for (Container container : containers) {
                Class<? extends ApplicationEvent> type = container.getClazz();
                ApplicationListener<? extends ApplicationEvent> listener = container.getListener();
                List<ApplicationListener<? extends ApplicationEvent>> list = mlisteners.get(type);
                if (list == null) {
                    list = new ArrayList<ApplicationListener<? extends ApplicationEvent>>();
                    mlisteners.put(type, list);
                }
                list.add(listener);
            }
            //TODO 初始化了EventKit及EventHandler。
            handler = new EventHandler(mlisteners, pool);
            EventKit.init(handler);
        } catch (Exception e) {
            LOG.error("EventPlugin start error!");
        }
    }


    public EventPlugin extendsPackage(String... packages) {
        inpackages = new ArrayList<String>(Arrays.asList(packages));
        return this;
    }

    public EventPlugin extendsJar(String... jars) {
        injars = new ArrayList<String>(Arrays.asList(jars));
        return this;
    }

    public EventPlugin excludeJar(String... jars) {
        for (String jar : jars) {
            injars.remove(jar);
        }
        return this;
    }

    /**
     * 
     * @Description: 事件监听临时容器
     * @Author wxming
     * @Date 2016年3月25日 下午2:38:02
     */
    class Container {
        private int priority;
        private Class<? extends ApplicationEvent> clazz;
        private ApplicationListener<? extends ApplicationEvent> listener;

        /**
         * @param priority
         * @param clazz
         * @param listener
         */
        public Container(int priority, Class<? extends ApplicationEvent> clazz,
                         ApplicationListener<? extends ApplicationEvent> listener) {
            super();
            this.priority = priority;
            this.clazz = clazz;
            this.listener = listener;
        }

        /**
         * Getter method for property <tt>priority</tt>.
         * 
         * @return property value of priority
         */
        public int getPriority() {
            return priority;
        }

        /**
         * Getter method for property <tt>clazz</tt>.
         * 
         * @return property value of clazz
         */
        public Class<? extends ApplicationEvent> getClazz() {
            return clazz;
        }

        /**
         * Getter method for property <tt>listener</tt>.
         * 
         * @return property value of listener
         */
        public ApplicationListener<? extends ApplicationEvent> getListener() {
            return listener;
        }
    }

    /**
     * 
     * @Description: 比较器
     * @Author wxming
     * @Date 2016年3月25日 下午5:20:03
     */
    class ContainerComparator implements Comparator<Container> {

        /**
         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
         */
        @Override
        public int compare(Container o1, Container o2) {
            Class<? extends ApplicationEvent> clazz1 = o1.getClazz();
            Class<? extends ApplicationEvent> clazz2 = o2.getClazz();
            if (clazz1.getSimpleName().compareTo(clazz2.getSimpleName()) == 1) {
                return 1;
            } else if (clazz1.getSimpleName().compareTo(clazz2.getSimpleName()) == 0) {
                int priority1 = o1.getPriority();
                int priority2 = o2.getPriority();
                if (priority1 > priority2) {
                    return 1;
                } else if (priority1 == priority2) {
                    return 0;
                } else {
                    return -1;
                }
            } else {
                return -1;
            }
        }

    }

}
